package cn.mw.cmdb.util;

import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.PropDesc;
import cn.mw.cmdb.entity.DataAuth;
import cn.mw.cmdb.entity.InputDataAuth;
import cn.mw.components.mongodb.anno.DataAuthAnno;
import cn.mw.components.mongodb.mapper.AggregateQueryFilter;
import cn.mw.components.mongodb.mapper.DefaultMethodMapper;
import cn.mw.components.mongodb.mapper.QueryFilter;
import cn.mw.microMonitorCommon.constants.SecurityConstants;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import com.alibaba.nacos.common.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@Slf4j
public class DataAuthQueryFilter implements QueryFilter , AggregateQueryFilter {

    private InputDataAuth inputDataAuth;

    public DataAuthQueryFilter(InputDataAuth inputDataAuth){
        this.inputDataAuth = inputDataAuth;
    }

    @Override
    public void filter(Query query, List<Criteria> criteriaList, DefaultMethodMapper mapper) {
        long time1 = System.currentTimeMillis();
        BeanDesc desc = BeanUtil.getBeanDesc(DataAuth.class);
        Iterator<PropDesc> ite = desc.getProps().iterator();

        Criteria groupCriteria = null;
        Criteria userCriteria = null;
        Criteria orgCriteria = null;

        String dataPerm = inputDataAuth.getDataPerm();
        if(!SecurityUtils.getUser().isAdmin()){
            while (ite.hasNext()){
                PropDesc propDesc = ite.next();
                Field field = propDesc.getField();
                DataAuthAnno annotation = field.getAnnotation(DataAuthAnno.class);
                if(null == annotation){
                    continue;
                }

                String key = annotation.value();
                String[] dataFields = key.split("\\.");
                List value = inputDataAuth.getAuthData(key);
                if(!CollectionUtils.isEmpty(value)){

                    if(InputDataAuth.OrgKey.equals(key)){
                        //如果是共有,则获取机构及其子机构数据
                        //如果是私有,则获取本机构数据
                        if(dataPerm.equals(SecurityConstants.DATA_PERM_PUBLIC)){
                            orgCriteria = Criteria.where(dataFields[0]).elemMatch(new Criteria().elemMatch(new Criteria().in(value)));
                        }else {
                            orgCriteria = Criteria.where(CMDBTool.getFieldName(DataAuth::getOrgIds)).in(value);
                        }
                    }else if(InputDataAuth.GroupKey.equals(key)) {
                        groupCriteria = Criteria.where(dataFields[0]).in(value);
                    }else if(InputDataAuth.UserKey.equals(key)){
                        userCriteria = Criteria.where(dataFields[0]).in(value);
                    }
                }
            }
        }
        criteriaList.add(Criteria.where(CMDBTool.getFieldName(DataAuth::getDataAuthType)).ne(null).ne(""));


        //如果为管理员角色,不做权限控制
        //相同用户组,可以互相查看数据
        //私有角色相同机构,不同责任人只能查看各自数据
        //共有角色,登录人员可以看到本机构,及其子机构数据
        List<Criteria> orCriterias = new ArrayList<>();
//        orCriterias.add(0,Criteria.where(CMDBTool.getFieldName(DataAuth::getDataAuthType)).is(DataAuthType.internal.name()));
        if(dataPerm.equals(SecurityConstants.DATA_PERM_PUBLIC)){
            if(null != groupCriteria){
                orCriterias.add(groupCriteria);
            }
            if(null != orgCriteria){
                orCriterias.add(orgCriteria);
            }
            if(null != userCriteria){
                orCriterias.add(userCriteria);
            }
        }else{
            if(null != groupCriteria){
                orCriterias.add(groupCriteria);
            }
            List<Criteria> andCriterias = new ArrayList<>();
            if(null != orgCriteria){
                andCriterias.add(orgCriteria);
            }
            if(null != userCriteria){
                andCriterias.add(userCriteria);
            }

            if(!andCriterias.isEmpty()){
                orCriterias.add(new Criteria().andOperator(andCriterias));
            }
        }

        if(orCriterias.size() > 0){
            criteriaList.add(new Criteria().orOperator(orCriterias));
        }
        long time2 = System.currentTimeMillis();
        log.info("权限参数耗时"+ (time2 - time1) + "ms");
    }

    @Override
    public void aggregateFilter(Class targetClass ,List<AggregationOperation> aggregationOperationList ,List<Criteria> criteriaList ,DefaultMethodMapper mapper) throws Exception {
        filter(null ,criteriaList ,null);
    }
}
